
#include <cstdio>
#include <BMap>
#include <BState>
#include <BFile>
#include <BSpring>
#include <BSpacer>
#include "IReadWrite.h"
#include "member_BImage.h"
#include "member_BResource.h"
#include "member_BWidget.h"
#include "member_BStyle.h"

using namespace BWE;

IReadWrite::IReadWrite()
{

}
IReadWrite::~IReadWrite()
{

}

bool IReadWrite::readObject(const BString& fileName, BObject* object)
{
	BString ext = fileName.ext();
	ext.lower();

	if (ext != "nos" && ext != "nodes")
		return false;

	BScene* scene = dynamic_cast<BScene*>(object);
	BNode* node = dynamic_cast<BNode*>(object);
	if (!scene && !node)
		return false;

	BFile file(fileName);
	if (!file.open(BFile::Mode_Read))
		return false;

	stream = &file;
	_states.clear();
	_materials.clear();
	_textures.clear();
	_programs.clear();

	BArray<BShapeHolder>		shapes;
	BArray<BNodeHolder>			nodes;

	Chunk chunk;
	while (stream->read(&chunk, 16))
	{
		if (chunk.sign < 0 || chunk.sign >= CHUNK_MAX)
		{
			printf("Error - Invalid Sign %d\n", chunk.sign);
			return false;
		}
		switch (chunk.sign)
		{
		case CHUNK_MESH:
		{
			BMesh* mesh = new BMesh();
			readMesh(mesh);
			shapes.append(mesh);
			break;
		}
		case CHUNK_GEOMETRY:
		{
			BGeometry* geometry = new BGeometry();
			readGeometry(geometry);
			shapes.append(geometry);
			break;
		}
		case CHUNK_NODE:
		{
			BNode* node = new BNode();
			readNode(node);
			nodes.append(node);
			break;
		}
		case CHUNK_LIGHT:
		{
			BLight* light = new BLight();
			readLight(light);
			nodes.append(light);
			break;
		}
		case CHUNK_CAMERA:
		{
			BCamera* camera = new BCamera();
			readCamera(camera);
			nodes.append(camera);
			break;
		}
		case CHUNK_STATE:
		{
			BState* state = new BState();
			readState(state);
			_states.append(state);
			break;
		}
		case CHUNK_MATERIAL:
		{
			BMaterial* material = new BMaterial();
			readMaterial(material);
			_materials.append(material);
			break;
		}
		case CHUNK_IMAGE:
		{
			BImage* image = new BImage();
			readImage(image);
			_textures.append(image);
			break;
		}
		case CHUNK_DISPLAY:
		{
			BDisplay* display = new BDisplay();
			readDisplay(display);
			_textures.append(display);
			break;
		}
		case CHUNK_PROGRAM:
		{
			BProgram* program = new BProgram();
			readProgram(program);
			_programs.append(program);
			break;
		}
		default:
			printf("Info - Don't read sign %d\n", chunk.sign);
			break;
		}
		stream->seek(chunk.end);
	}

	if (scene)
	{
		for (int i = 0; i < shapes.size(); i++)
		{
			BShape* shape = shapes[i];
			scene->inserts(shape);
		}
		for (int i = 0; i < nodes.size(); i++)
		{
			BNode* node = nodes[i];
			scene->inserts(node);
		}
	}
	return true;
}
bool IReadWrite::writeObject(const BString& fileName, const BObject* object)
{
	if (!object)
		return false;

	const BScene* scene = dynamic_cast<const BScene*>(object);
	const BNode* node = dynamic_cast<const BNode*>(object);
	if (!scene && !node)
		return false;

	BString ext = fileName.ext();
	ext.lower();
	if (ext != "nos" && ext != "nodes")
		return false;

	BFile file(fileName);
	if (!file.open(BFile::Mode_Write))
		return false;
	stream = &file;

	_states.clear();
	_materials.clear();
	_textures.clear();
	_programs.clear();

	if (!writeSMTP(scene, node))
		return false;

	if (scene)
	{
		for (int i = 0; i < scene->shapeCount(); i++)
		{
			const BShape* shape = scene->shape(i);
			if (!writeShape(shape))
			{
				printf("Error -- write shape failed : %s\n", shape->name().cstr());
				return false;
			}
		}
		for (int i = 0; i < scene->nodeCount(); i++)
		{
			const BNode* node = scene->node(i);
			if (!writeNode(node))
			{
				printf("Error -- write node failed : %s\n", node->name().cstr());
				return false;
			}
		}
	}
	else
	{
		if (!writeNode(node))
		{
			printf("Error -- write node failed : %s\n", node->name().cstr());
			return false;
		}
	}

	return true;
}

bool IReadWrite::readMaterial(BMaterial* material)
{
	Chunk chunk;
	while (stream->read(&chunk, 16))
	{
		switch (chunk.sign)
		{
		case CHUNK_NAME:
		{
			BString name;
			stream->read(name);
			material->setName(name);
			break;
		}
		case CHUNK_ENABLE:
		{
			bool enable = false;
			stream->read(enable);
			material->setAble(enable);
			break;
		}
		case CHUNK_AMBIENT:
		{
			BColor ambient;
			stream->read(ambient);
			material->setAmbient(ambient);
			break;
		}
		case CHUNK_DIFFUSE:
		{
			BColor diffuse;
			stream->read(diffuse);
			material->setDiffuse(diffuse);
			break;
		}
		case CHUNK_SPECULAR:
		{
			BColor specular;
			stream->read(specular);
			material->setSpecular(specular);
			break;
		}
		case CHUNK_EMISSION:
		{
			BColor emission;
			stream->read(emission);
			material->setEmission(emission);
			break;
		}
		case CHUNK_SHININESS:
		{
			float shininess;
			stream->read(shininess);
			material->setShininess(shininess);
			break;
		}
		default:
			break;
		}
		stream->seek(chunk.end);
	}
	return true;
}
bool IReadWrite::readImage(BImage* image)
{
	Chunk chunk;
	while (stream->read(&chunk, 16))
	{
		switch (chunk.sign)
		{
		case CHUNK_NAME:
		{
			BString name;
			stream->read(name);
			image->setName(name);
			break;
		}
		case CHUNK_ENABLE:
		{
			bool enable = false;
			stream->read(enable);
			image->setAble(enable);
			break;
		}
		case CHUNK_BLEND:
		{
			BTexture::Blend blend = BTexture::Blend_None;
			stream->read(blend);
			image->setBlend(blend);
			break;
		}
		case CHUNK_WRAP:
		{
			BTexture::Wrap wrap = BTexture::Wrap_None;
			stream->read(wrap);
			image->setWrap(wrap);
			break;
		}
		case CHUNK_FILTER:
		{
			BTexture::Filter filter = BTexture::Filter_None;
			stream->read(filter);
			image->setFilter(filter);
			break;
		}
		case CHUNK_MIPMAP:
		{
			bool mipmap = false;
			stream->read(mipmap);
			image->setMipmap(mipmap);
			break;
		}
		case CHUNK_BLENDCOLOR:
		{
			BColor blendColor;
			stream->read(blendColor);
			image->setBlendColor(blendColor);
			break;
		}
		case CHUNK_FILENAME:
		{
			BString fileName;
			stream->read(fileName);
			if (!ReadObject(fileName, image))
			{
				printf("Error - Read image file failed : %s\n", fileName.cstr());
			}
			break;
		}
		case CHUNK_FORMAT:
		{
			Format format = Format_None;
			stream->read(format);
			image->setFormat(format);
			break;
		}
		case CHUNK_SIZE:
		{
			BSize size;
			stream->read(size);
			image->setSize(size);
			break;
		}
		case CHUNK_PIXELS:
		{
			int size = 0;
			stream->read(size);
			BByteArray* pixels = new BByteArray(size);
			stream->read(pixels->data(), size);
			image->setPixels(pixels);
			break;
		}
		default:
			break;
		}
		stream->seek(chunk.end);
	}
	return true;
}
bool IReadWrite::readDisplay(BDisplay* display)
{
	Chunk chunk;
	while (stream->read(&chunk, 16))
	{
		switch (chunk.sign)
		{
		case CHUNK_NAME:
		{
			BString name;
			stream->read(name);
			display->setName(name);
			break;
		}
		case CHUNK_ENABLE:
		{
			bool enable = false;
			stream->read(enable);
			display->setAble(enable);
			break;
		}
		case CHUNK_BLEND:
		{
			BTexture::Blend blend = BTexture::Blend_None;
			stream->read(blend);
			display->setBlend(blend);
			break;
		}
		case CHUNK_WRAP:
		{
			BTexture::Wrap wrap = BTexture::Wrap_None;
			stream->read(wrap);
			display->setWrap(wrap);
			break;
		}
		case CHUNK_FILTER:
		{
			BTexture::Filter filter = BTexture::Filter_None;
			stream->read(filter);
			display->setFilter(filter);
			break;
		}
		case CHUNK_MIPMAP:
		{
			bool mipmap = false;
			stream->read(mipmap);
			display->setMipmap(mipmap);
			break;
		}
		case CHUNK_BLENDCOLOR:
		{
			BColor blendColor;
			stream->read(blendColor);
			display->setBlendColor(blendColor);
			break;
		}
		case CHUNK_SIZE:
		{
			BSize size;
			stream->read(size);
			display->setSize(size);
			break;
		}
		case CHUNK_BACKGROUND:
		{
			BColor background;
			stream->read(background);
			display->setBackground(background);
			break;
		}
		default:
			break;
		}
		stream->seek(chunk.end);
	}
	return true;
}
bool IReadWrite::readState(BState* state)
{
	Chunk chunk;
	while (stream->read(&chunk, 16))
	{
		switch (chunk.sign)
		{
		case CHUNK_NAME:
		{
			BString name;
			stream->read(name);
			state->setName(name);
			break;
		}
		case CHUNK_ENABLE:
		{
			bool enable = false;
			stream->read(enable);
			state->setAble(enable);
			break;
		}
		case CHUNK_LIGHTING:
		{
			bool lighting = false;
			stream->read(lighting);
			state->setLighting(lighting);
			break;
		}
		case CHUNK_DEPTHTEST:
		{
			bool depthTest = false;
			stream->read(depthTest);
			state->setDepthTest(depthTest);
			break;
		}
		case CHUNK_CULLBACK:
		{
			bool cullBack = false;
			stream->read(cullBack);
			state->setCullBack(cullBack);
			break;
		}
		case CHUNK_NORMALIZE:
		{
			bool normalize = false;
			stream->read(normalize);
			state->setNormalize(normalize);
			break;
		}
		case CHUNK_POINTSMOOTH:
		{
			bool smooth = false;
			stream->read(smooth);
			state->setPointSmooth(smooth);
			break;
		}
		case CHUNK_LINESMOOTH:
		{
			bool smooth = false;
			stream->read(smooth);
			state->setLineSmooth(smooth);
			break;
		}
		case CHUNK_POINTSIZE:
		{
			int pointSize = 0;
			stream->read(pointSize);
			state->setPointSize(pointSize);
			break;
		}
		case CHUNK_LINEWIDTH:
		{
			int lineWidth = 0;
			stream->read(lineWidth);
			state->setLineWidth(lineWidth);
			break;
		}
		case CHUNK_POLYGONMODE:
		{
			PolygonMode polyMode = Polygon_Fill;
			stream->read(polyMode);
			state->setPolygonMode(polyMode);
			break;
		}
		default:
			break;
		}
		stream->seek(chunk.end);
	}
	return true;
}
bool IReadWrite::readProgram(BProgram* program)
{
	Chunk chunk;
	while (stream->read(&chunk, 16))
	{
		switch (chunk.sign)
		{
		case CHUNK_NAME:
		{
			BString name;
			stream->read(name);
			program->setName(name);
			break;
		}
		case CHUNK_ENABLE:
		{
			bool enable = false;
			stream->read(enable);
			program->setAble(enable);
			break;
		}
		case CHUNK_SHADER:
		{
			BShader* shader = new BShader();
			readShader(shader);
			program->addShader(shader);
			break;
		}
		case CHUNK_UNIFORM:
		{
			BUniform* uniform = new BUniform();
			readUniform(uniform);
			program->addUniform(uniform);
			break;
		}
		default:
			break;
		}
		stream->seek(chunk.end);
	}
	return true;
}
bool IReadWrite::readShader(BShader* shader)
{
	Chunk chunk;
	while (stream->read(&chunk, 16))
	{
		switch (chunk.sign)
		{
		case CHUNK_NAME:
		{
			BString name;
			stream->read(name);
			shader->setName(name);
			break;
		}
		case CHUNK_ENABLE:
		{
			bool enable = false;
			stream->read(enable);
			shader->setAble(enable);
			break;
		}
		case CHUNK_TYPE:
		{
			ShaderType type = Shader_None;
			stream->read(type);
			shader->setType(type);
			break;
		}
		case CHUNK_TEXT:
		{
			BString text;
			stream->read(text);
			shader->setText(text);
			break;
		}
		default:
			break;
		}
		stream->seek(chunk.end);
	}
	return true;
}
bool IReadWrite::readUniform(BUniform* uniform)
{
	Chunk chunk;
	while (stream->read(&chunk, 16))
	{
		switch (chunk.sign)
		{
		case CHUNK_NAME:
		{
			BString name;
			stream->read(name);
			uniform->setName(name);
			break;
		}
		case CHUNK_ENABLE:
		{
			bool enable = false;
			stream->read(enable);
			uniform->setAble(enable);
			break;
		}
		case CHUNK_SIGN:
		{
			BString sign;
			stream->read(sign);
			uniform->setSign(sign);
			break;
		}
		case CHUNK_TYPE:
		{
			BUniform::Type type = BUniform::Type_None;
			stream->read(type);
			uniform->setType(type);
			break;
		}
		case CHUNK_SIZE:
		{
			int size = 0;
			stream->read(size);
			uniform->setSize(size);
			break;
		}
		default:
			break;
		}
		stream->seek(chunk.end);
	}
	return true;
}
bool IReadWrite::readFont(BFont* font)
{
	return true;
}

bool IReadWrite::readNode(BNode* node)
{
	return true;
}
bool IReadWrite::readLight(BLight* light)
{
	return true;
}
bool IReadWrite::readCamera(BCamera* camera)
{
	return true;
}

bool IReadWrite::readMesh(BMesh* mesh)
{
	return true;
}
bool IReadWrite::readGeometry(BGeometry* geometry)
{
	Chunk chunk;
	while (stream->read(&chunk, 16))
	{
		printf("chunk %d (%d, %d)\n",chunk.sign, chunk.begin, chunk.end);
		switch (chunk.sign)
		{
		case CHUNK_NAME:
		{
			BString name;
			stream->read(name);
			geometry->setName(name);
			break;
		}
		case CHUNK_ENABLE:
		{
			bool enable = false;
			stream->read(enable);
			geometry->setAble(enable);
			break;
		}
		case CHUNK_MATRIX:
		{
			BMatrix matrix;
			stream->read(matrix);
			geometry->setMatrix(matrix);
			break;
		}
		case CHUNK_STATE_ID:
		{
			int stateId = 0;
			stream->read(stateId);
			BState* state = _states(stateId);
			geometry->setState(state);
			break;
		}
		case CHUNK_MATERIAL_ID:
		{
			int matId = 0;
			stream->read(matId);
			BMaterial* material = _materials(matId);
			geometry->setMaterial(material);
			break;
		}
		case CHUNK_TEXTURE_ID:
		{
			int texId = 0;
			stream->read(texId);
			BTexture* texture = _textures(texId);
			geometry->setTexture(texture);
			break;
		}
		case CHUNK_PROGRAM_ID:
		{
			int proId = 0;
			stream->read(proId);
			BProgram* program = _programs(proId);
			geometry->setProgram(program);
			break;
		}
		case CHUNK_VERTICES:
		{
			int size = 0;
			stream->read(size);
			BVectorArray* vertices = new BVectorArray(size);
			stream->read(vertices->data(), size * sizeof(BVector));
			geometry->setVertices(vertices);
			break;
		}
		case CHUNK_NORMALS:
		{
			int size = 0;
			stream->read(size);
			BVectorArray* normals = new BVectorArray(size);
			stream->read(normals->data(), size * sizeof(BVector));
			geometry->setNormals(normals);
			break;
		}
		case CHUNK_TEXCOORDS:
		{
			int size = 0;
			stream->read(size);
			BCoordArray* texCoords = new BCoordArray(size);
			stream->read(texCoords->data(), size * sizeof(BCoord));
			geometry->setTexCoords(texCoords);
			break;
		}
		case CHUNK_ELEMENT:
		{
			BElement* element = new BElement();
			readElement(element);
			geometry->addElement(element);
			break;
		}
		default:
			break;
		}
		stream->seek(chunk.end);
	}
	return true;
}
bool IReadWrite::readElement(BElement* element)
{
	Chunk chunk;
	while (stream->read(&chunk, 16))
	{
		printf("chunk %d (%d, %d)\n", chunk.sign, chunk.begin, chunk.end);
		switch (chunk.sign)
		{
		case CHUNK_NAME:
		{
			BString name;
			stream->read(name);
			element->setName(name);
			break;
		}
		case CHUNK_ENABLE:
		{
			bool enable = false;
			stream->read(enable);
			element->setAble(enable);
			break;
		}
		case CHUNK_PRIMITIVE:
		{
			Primitive primitive = Primitive_None;
			stream->read(primitive);
			element->setPrimitive(primitive);
			break;
		}
		case CHUNK_FIRST:
		{
			int first = 0;
			stream->read(first);
			element->setFirst(first);
			break;
		}
		case CHUNK_COUNT:
		{
			int count = 0;
			stream->read(count);
			element->setCount(count);
			break;
		}
		case CHUNK_INDICES:
		{
			int size = 0;
			stream->read(size);
			BIndexArray* indices = new BIndexArray(size);
			stream->read(indices->data(), size * sizeof(int));
			element->setIndices(indices);
			break;
		}
		default:
			break;
		}
		stream->seek(chunk.end);
	}
	return true;
}

bool IReadWrite::writeSMTP(const BScene* scene, const BNode* node)
{
	BArray<const BShape*> shapes;
	if (scene)
	{
		for (int i = 0; i < scene->shapeCount(); i++)
		{
			const BShape* shape = scene->shape(i);
			shapes.append(shape);
		}
		for (int i = 0; i < scene->nodeCount(); i++)
		{
			const BNode* node = scene->node(i);
			for (int si = 0; si < scene->shapeCount(); si++)
			{
				const BShape* shape = node->shape(si);
				shapes.append(shape);
			}
		}
	}
	else
	{
		for (int si = 0; si < scene->shapeCount(); si++)
		{
			const BShape* shape = node->shape(si);
			shapes.append(shape);
		}
	}

	for (int i = 0; i < shapes.size(); i++)
	{
		const BShape* shape = shapes[i];
		if (BState* state = shape->state())
			_states.append(state);
		if (BMaterial* material = shape->material())
			_materials.append(material);
		if (BTexture* texture = shape->texture())
			_textures.append(texture);
		if (BProgram* program = shape->program())
			_programs.append(program);
	}

	for (int i = 0; i < _states.size(); i++)
	{
		BState* state = _states[i];
		if (!writeState(state))
		{
			printf("Error -- write state failed : %s\n", state->name().cstr());
			return false;
		}
	}

	for (int i = 0; i < _materials.size(); i++)
	{
		BMaterial* material = _materials[i];
		if (!writeMaterial(material))
		{
			printf("Error -- write material failed : %s\n", material->name().cstr());
			return false;
		}
	}

	for (int i = 0; i < _textures.size(); i++)
	{
		BTexture* texture = _textures[i];
		if (!writeTexture(texture))
		{
			printf("Error -- write texture failed : %s\n", texture->name().cstr());
			return false;
		}
	}

	for (int i = 0; i < _programs.size(); i++)
	{
		BProgram* program = _programs[i];
		if (!writeProgram(program))
		{
			printf("Error -- write program failed : %s\n", program->name().cstr());
			return false;
		}
	}
	return true;
}

bool IReadWrite::writeObjectData(const BObject* object)
{
	if (!object)
		return false;
	{
		AutoChunk chunk(stream, CHUNK_NAME);
		stream->write(object->name());
	}
	{
		AutoChunk chunk(stream, CHUNK_ENABLE);
		stream->write(object->able());
	}
	return true;
}
bool IReadWrite::writeNodeData(const BNode* node)
{
	if (!node)
		return false;
	{
		AutoChunk chunk(stream, CHUNK_VISIBLE);
		stream->write(node->visible());
	}
	{
		AutoChunk chunk(stream, CHUNK_MATRIX);
		stream->write(node->matrix());
	}
	for (int i = 0; i < node->shapeCount(); i++)
	{
		const BShape* shape = node->shape(i);
		writeShape(shape);
	}
	return true;
}
bool IReadWrite::writeShapeData(const BShape* shape)
{
	if (!shape)
		return false;
	{
		AutoChunk chunk(stream, CHUNK_SPACE);
		stream->write(shape->space());
	}
	if (BMaterial* material = shape->material())
	{
		if (!_materials.contain(material))
			_materials.append(material);
		int id = _materials.find(material);
		AutoChunk chunk(stream, CHUNK_MATERIAL_ID);
		stream->write(id);
	}
	if (BTexture* texture = shape->texture())
	{
		if (!_textures.contain(texture))
			_textures.append(texture);
		int id = _textures.find(texture);
		AutoChunk chunk(stream, CHUNK_TEXTURE_ID);
		stream->write(id);
	}
	if (BProgram* program = shape->program())
	{
		if (!_programs.contain(program))
			_programs.append(program);
		int id = _programs.find(program);
		AutoChunk chunk(stream, CHUNK_PROGRAM_ID);
		stream->write(id);
	}
	if (BState* state = shape->state())
	{
		if (!_states.contain(state))
			_states.append(state);
		int id = _states.find(state);
		AutoChunk chunk(stream, CHUNK_STATE_ID);
		stream->write(id);
	}
	return true;
}
bool IReadWrite::writeTextureData(const BTexture* texture)
{
	if (!texture)
		return false;

	{
		AutoChunk chunk(stream, CHUNK_BLEND);
		int blend = texture->blend();
		stream->write(blend);
	}
	{
		AutoChunk chunk(stream, CHUNK_BLENDCOLOR);
		BColor color = texture->blendColor();
		stream->write(color);
	}
	{
		AutoChunk chunk(stream, CHUNK_FILTER);
		int filter = texture->filter();
		stream->write(filter);
	}
	{
		AutoChunk chunk(stream, CHUNK_WRAP);
		int wrap = texture->wrap();
		stream->write(wrap);
	}
	{
		AutoChunk chunk(stream, CHUNK_MIPMAP);
		bool mipmap = texture->mipmap();
		stream->write(mipmap);
	}

	return true;
}

bool IReadWrite::writeNode(const BNode* node)
{
	if (const BLight* light = dynamic_cast<const BLight*>(node))
	{
		return writeLight(light);
	}
	if (const BCamera* camera = dynamic_cast<const BCamera*>(node))
	{
		return writeCamera(camera);
	}
	AutoChunk chunk(stream, CHUNK_NODE);
	writeObjectData(node);
	writeNodeData(node);
	return true;
}
bool IReadWrite::writeLight(const BLight* light)
{
	AutoChunk chunk(stream, CHUNK_LIGHT);

	writeObjectData(light);
	writeNodeData(light);
	{
		AutoChunk chunk(stream, CHUNK_AMBIENT);
		BColor ambient = light->ambient();
		stream->write(ambient);
	}
	{
		AutoChunk chunk(stream, CHUNK_DIFFUSE);
		BColor diffuse = light->diffuse();
		stream->write(diffuse);
	}
	{
		AutoChunk chunk(stream, CHUNK_SPECULAR);
		BColor specular = light->specular();
		stream->write(specular);
	}
	{
		AutoChunk chunk(stream, CHUNK_ATTENUATION);
		float attenuation = light->attenuation();
		stream->write(attenuation);
	}
	{
		AutoChunk chunk(stream, CHUNK_ATTENUATION2);
		float attenuation2 = light->attenuation2();
		stream->write(attenuation2);
	}

	return true;
}
bool IReadWrite::writeCamera(const BCamera* camera)
{
	AutoChunk chunk(stream, CHUNK_CAMERA);

	writeObjectData(camera);
	writeNodeData(camera);

	{
		AutoChunk chunk(stream, CHUNK_CENTER);
		BVector center = camera->center();
		stream->write(center);
	}
	{
		AutoChunk chunk(stream, CHUNK_UP);
		BVector up = camera->up();
		stream->write(up);
	}
	{
		AutoChunk chunk(stream, CHUNK_NEAR);
		float near = camera->near();
		stream->write(near);
	}
	{
		AutoChunk chunk(stream, CHUNK_FAR);
		float far = camera->far();
		stream->write(far);
	}
	return true;
}

bool IReadWrite::writeShape(const BShape* shape)
{
	if (const BMesh* mesh = dynamic_cast<const BMesh*>(shape))
	{
		return writeMesh(mesh);
	}
	if (const BGeometry* geometry = dynamic_cast<const BGeometry*>(shape))
	{
		return writeGeometry(geometry);
	}
	return false;
}
bool IReadWrite::writeMesh(const BMesh* mesh)
{
	AutoChunk chunk(stream, CHUNK_MESH);
	writeObjectData(mesh);
	writeShapeData(mesh);
	const BVectorArray* vertices = mesh->vertices();
	if (vertices)
	{
		AutoChunk chunk(stream, CHUNK_VERTICES);
		int size = vertices->size();
		stream->write(&size);
		stream->write(vertices->data(), size * 12);
	}
	const BVectorArray* normals = mesh->normals();
	if (normals)
	{
		AutoChunk chunk(stream, CHUNK_NORMALS);
		int size = normals->size();
		stream->write(size);
		stream->write(normals->data(), size * 12);
	}
	const BCoordArray* texCoords = mesh->texCoords();
	if (texCoords)
	{
		AutoChunk chunk(stream, CHUNK_TEXCOORDS);
		int size = texCoords->size();
		stream->write(size);
		stream->write(texCoords->data(), size * 8);
	}
	const BFaceArray* faces = mesh->faces();
	if (faces)
	{
		AutoChunk chunk(stream, CHUNK_FACES);
		int size = faces->size();
		stream->write(size);
		stream->write(faces->data(), size * 12);
	}
	return true;
}
bool IReadWrite::writeGeometry(const BGeometry* geometry)
{
	AutoChunk chunk(stream, CHUNK_GEOMETRY);
	writeObjectData(geometry);
	writeShapeData(geometry);
	const BVectorArray* vertices = geometry->vertices();
	if (vertices)
	{
		AutoChunk chunk(stream, CHUNK_VERTICES);
		int size = vertices->size();
		stream->write(size);
		stream->write(vertices->data(), size * 12);
	}
	const BVectorArray* normals = geometry->normals();
	if (normals)
	{
		AutoChunk chunk(stream, CHUNK_NORMALS);
		int size = normals->size();
		stream->write(size);
		stream->write(normals->data(), size * 12);
	}
	const BCoordArray* texCoords = geometry->texCoords();
	if (texCoords)
	{
		AutoChunk chunk(stream, CHUNK_TEXCOORDS);
		int size = texCoords->size();
		stream->write(size);
		stream->write(texCoords->data(), size * 8);
	}
	for (int i = 0; i < geometry->elementCount(); i++)
	{
		const BElement* element = geometry->element(i);
		writeElement(element);
	}
	return true;
}
bool IReadWrite::writeElement(const BElement* element)
{
	AutoChunk chunk(stream, CHUNK_ELEMENT);
	writeObjectData(element);
	{
		AutoChunk chunk(stream, CHUNK_PRIMITIVE);
		int primitive = element->primitive();
		stream->write(primitive);
	}
	{
		AutoChunk chunk(stream, CHUNK_FIRST);
		int first = element->first();
		stream->write(first);
	}
	{
		AutoChunk chunk(stream, CHUNK_COUNT);
		int count = element->count();
		stream->write(count);
	}
	BIndexArray* indices = element->indices();
	if (indices)
	{
		AutoChunk chunk(stream, CHUNK_INDICES);
		int size = indices->size();
		stream->write(size);
		stream->write(indices->data(), size * 4);
	}
	return true;
}

bool IReadWrite::writeCube(const BCube* cube)
{
	return true;
}
bool IReadWrite::writeCylinder(const BCylinder* cylinder)
{
	return true;
}
bool IReadWrite::writeSphere(const BSphere* sphere)
{
	return true;
}
bool IReadWrite::writeTorus(const BTorus* torus)
{
	return true;
}

bool IReadWrite::writeState(const BState* state)
{
	AutoChunk chunk(stream, CHUNK_STATE);
	writeObjectData(state);
	{
		AutoChunk chunk(stream, CHUNK_LIGHTING);
		bool lighting = state->lighting();
		stream->write(lighting);
	}
	{
		AutoChunk chunk(stream, CHUNK_DEPTHTEST);
		bool depthTest = state->depthTest();
		stream->write(depthTest);
	}
	{
		AutoChunk chunk(stream, CHUNK_NORMALIZE);
		bool normalize = state->normalize();
		stream->write(normalize);
	}
	{
		AutoChunk chunk(stream, CHUNK_LINESMOOTH);
		bool smooth = state->lineSmooth();
		stream->write(smooth);
	}
	{
		AutoChunk chunk(stream, CHUNK_LINEWIDTH);
		int width = state->lineWidth();
		stream->write(width);
	}
	{
		AutoChunk chunk(stream, CHUNK_POINTSMOOTH);
		bool smooth = state->pointSmooth();
		stream->write(smooth);
	}
	{
		AutoChunk chunk(stream, CHUNK_POINTSIZE);
		int pointSize = state->pointSize();
		stream->write(pointSize);
	}
	{
		AutoChunk chunk(stream, CHUNK_POLYGONMODE);
		int polygonMode = state->polygonMode();
		stream->write(polygonMode);
	}
	{
		AutoChunk chunk(stream, CHUNK_CULLBACK);
		bool cullBack = state->cullBack();
		stream->write(cullBack);
	}
	return true;
}
bool IReadWrite::writeMaterial(const BMaterial* material)
{
	AutoChunk chunk(stream, CHUNK_MATERIAL);
	writeObjectData(material);
	{
		AutoChunk chunk(stream, CHUNK_AMBIENT);
		BColor ambient = material->ambient();
		stream->write(ambient);
	}
	{
		AutoChunk chunk(stream, CHUNK_DIFFUSE);
		BColor diffuse = material->diffuse();
		stream->write(diffuse);
	}
	{
		AutoChunk chunk(stream, CHUNK_SPECULAR);
		BColor specular = material->specular();
		stream->write(specular);
	}
	{
		AutoChunk chunk(stream, CHUNK_EMISSION);
		BColor emission = material->emission();
		stream->write(emission);
	}
	{
		AutoChunk chunk(stream, CHUNK_SHININESS);
		float shininess = material->shininess();
		stream->write(shininess);
	}
	return true;
}

bool IReadWrite::writeTexture(const BTexture* texture)
{
	if (const BImage* image = dynamic_cast<const BImage*>(texture))
	{
		return writeImage(image);
	}
	if (const BDisplay* display = dynamic_cast<const BDisplay*>(texture))
	{
		return writeDisplay(display);
	}
	return false;
}
bool IReadWrite::writeImage(const BImage* image)
{
	AutoChunk chunk(stream, CHUNK_IMAGE);
	writeObjectData(image);
	writeTextureData(image);
	const BString& fileName = image->fileName();
	if (fileName.size())
	{
		AutoChunk chunk(stream, CHUNK_FILENAME);
		stream->write(fileName);
		return true;
	}
	else
	{
		{
			AutoChunk chunk(stream, CHUNK_FORMAT);
			int format = image->format();
			stream->write(format);
		}
		{
			AutoChunk chunk(stream, CHUNK_SIZE);
			BSize size = image->size();
			stream->write(size);
		}
		const BByteArray* pixels = image->pixels();
		if (pixels)
		{
			AutoChunk chunk(stream, CHUNK_PIXELS);
			int size = pixels->size();
			stream->write(size);
			stream->write(pixels->data(), size);
		}
	}
	return true;
}
bool IReadWrite::writeDisplay(const BDisplay* display)
{
	AutoChunk chunk(stream, CHUNK_DISPLAY);
	writeObjectData(display);
	writeTextureData(display);
	{
		AutoChunk chunk(stream, CHUNK_SIZE);
		BSize size = display->size();
		stream->write(size);
	}

	return true;
}
bool IReadWrite::writeProgram(const BProgram* program)
{
	if (!program)
		return false;
	AutoChunk chunk(stream, CHUNK_PROGRAM);
	writeObjectData(program);
	for (int i = 0; i < program->shaderCount(); i++)
	{
		const BShader* shader = program->shader(i);
		writeShader(shader);
	}
	for (int i = 0; i < program->uniformCount(); i++)
	{
		const BUniform* uniform = program->uniform(i);
		writeUniform(uniform);
	}
	return true;
}
bool IReadWrite::writeShader(const BShader* shader)
{
	AutoChunk chunk(stream, CHUNK_SHADER);
	writeObjectData(shader);
	{
		AutoChunk chunk(stream, CHUNK_TYPE);
		int type = shader->type();
		stream->write(type);
	}
	{
		AutoChunk chunk(stream, CHUNK_TEXT);
		const BString& text = shader->text();
		stream->write(text);
	}
	return true;
}
bool IReadWrite::writeUniform(const BUniform* uniform)
{
	AutoChunk chunk(stream, CHUNK_UNIFORM);
	writeObjectData(uniform);
	{
		AutoChunk chunk(stream, CHUNK_SIGN);
		const BString& sign = uniform->sign();
		stream->write(sign);
	}
	{
		AutoChunk chunk(stream, CHUNK_TYPE);
		int type = uniform->type();
		stream->write(type);
	}
	{
		AutoChunk chunk(stream, CHUNK_SIZE);
		int size = uniform->size();
		stream->write(size);
	}
	return true;
}

bool IReadWrite::writeFont(const BFont* font)
{
	writeObjectData(font);

	return true;
}


